home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / emulator / uae-0.000 / uae-0 / uae-0.6.0 / filesys.c < prev    next >
C/C++ Source or Header  |  1996-06-12  |  38KB  |  1,716 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * (c) 1996 Ed Hanway
  7.   *
  8.   * Version 0.1: 28-Jan-1996
  9.   *
  10.   * Based on example code (c) 1988 The Software Distillery
  11.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  12.   * (May - August 1989)
  13.   *
  14.   * Known limitations:
  15.   * Does not support ACTION_INHIBIT (big deal).
  16.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  17.   * Does not actually enforce exclusive locks.
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   *
  23.   * TODO someday:
  24.   * Support booting.
  25.   * Implement real locking using flock.  Needs test cases.
  26.   */
  27.  
  28. #include "sysconfig.h"
  29. #include "sysdeps.h"
  30.  
  31. #include "config.h"
  32. #include "options.h"
  33. #include "events.h"
  34. #include "memory.h"
  35. #include "custom.h"
  36. #include "newcpu.h"
  37. #include "xwin.h"
  38. #include "autoconf.h"
  39. #include "filesys.h"
  40.  
  41. #define MAKE_CASE_INSENSITIVE
  42.  
  43. typedef struct {
  44.     char *devname; /* device name, e.g. UAE0: */
  45.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  46.     char *rootdir; /* root unix directory */
  47.     int readonly; /* disallow write access? */
  48. } UnitInfo;
  49.  
  50. #define MAX_UNITS 20
  51. static int num_units = 0;
  52. static UnitInfo ui[MAX_UNITS];
  53.  
  54. static ULONG devnameaddr[100];
  55.  
  56. static ULONG doslibname, fsdevname, filesysseglist;
  57.  
  58. void
  59. add_filesys_unit(char *volname, char *rootdir, int readonly)
  60. {
  61.     UnitInfo* u;
  62.     static char buf[80];
  63.  
  64.     if (num_units >= MAX_UNITS) {
  65.     fprintf(stderr, "Maximum number of unix file systems mounted.\n");
  66.     return;
  67.     }
  68.  
  69.     u = &ui[num_units];
  70.     sprintf(buf, "UAE%d", num_units);
  71.     u->devname = my_strdup(buf);
  72.     u->volname = my_strdup(volname);
  73.     u->rootdir = my_strdup(rootdir);
  74.     u->readonly = readonly;
  75.  
  76.     num_units++;
  77. }
  78.  
  79. #ifdef TRACING_ENABLED
  80. #define TRACE(x)    printf x;
  81. #define DUMPLOCK(x)    dumplock(x)
  82. #else
  83. #define TRACE(x)
  84. #define DUMPLOCK(x)
  85. #endif
  86.  
  87. /* minimal AmigaDOS definitions */
  88.  
  89. /* field offsets in DosPacket */
  90. #define dp_Type (8)
  91. #define dp_Res1    (12)
  92. #define dp_Res2 (16)
  93. #define dp_Arg1 (20)
  94. #define dp_Arg2 (24)
  95. #define dp_Arg3 (28)
  96. #define dp_Arg4 (32)
  97.  
  98. /* result codes */
  99. #define DOS_TRUE (-1L)
  100. #define DOS_FALSE (0L)
  101.  
  102. /* packet types */
  103. #define ACTION_CURRENT_VOLUME    7
  104. #define ACTION_LOCATE_OBJECT    8
  105. #define ACTION_RENAME_DISK    9
  106. #define ACTION_FREE_LOCK    15
  107. #define ACTION_DELETE_OBJECT    16
  108. #define ACTION_RENAME_OBJECT    17
  109. #define ACTION_COPY_DIR        19
  110. #define ACTION_SET_PROTECT    21
  111. #define ACTION_CREATE_DIR    22
  112. #define ACTION_EXAMINE_OBJECT    23
  113. #define ACTION_EXAMINE_NEXT    24
  114. #define ACTION_DISK_INFO    25
  115. #define ACTION_INFO        26
  116. #define ACTION_FLUSH        27
  117. #define ACTION_SET_COMMENT    28
  118. #define ACTION_PARENT        29
  119. #define ACTION_SET_DATE        34
  120. #define ACTION_SAME_LOCK    40
  121. #define ACTION_FIND_WRITE    1004
  122. #define ACTION_FIND_INPUT    1005
  123. #define ACTION_FIND_OUTPUT    1006
  124. #define ACTION_END        1007
  125. #define ACTION_SEEK        1008
  126. #define ACTION_IS_FILESYSTEM    1027
  127. #define ACTION_READ        'R'
  128. #define ACTION_WRITE        'W'
  129.  
  130. #define DISK_TYPE        (0x444f5301) /* DOS\1 */
  131.  
  132. /* errors */
  133. #define ERROR_NO_FREE_STORE     103
  134. #define ERROR_OBJECT_IN_USE    202
  135. #define ERROR_OBJECT_EXISTS     203
  136. #define ERROR_DIR_NOT_FOUND     204
  137. #define ERROR_OBJECT_NOT_FOUND  205
  138. #define ERROR_ACTION_NOT_KNOWN  209
  139. #define ERROR_OBJECT_WRONG_TYPE 212
  140. #define ERROR_DISK_WRITE_PROTECTED 214
  141. #define ERROR_DIRECTORY_NOT_EMPTY 216
  142. #define ERROR_DEVICE_NOT_MOUNTED 218
  143. #define ERROR_SEEK_ERROR    219
  144. #define ERROR_DISK_FULL        221
  145. #define ERROR_WRITE_PROTECTED 223
  146. #define ERROR_NO_MORE_ENTRIES  232
  147. #define ERROR_NOT_IMPLEMENTED    236
  148.  
  149. static long dos_errno(void)
  150. {
  151.     int e = errno;
  152.  
  153.     switch(e) {
  154.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  155.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  156.      case EACCES:    return ERROR_WRITE_PROTECTED;
  157.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  158.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  159.      case ENOSPC:    return ERROR_DISK_FULL;
  160.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  161.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  162. #if !defined(__bebox__) && !defined(__DOS__)
  163.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  164. #endif
  165. #ifndef AMIGA
  166.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  167.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  168. #endif
  169.  
  170.      default:
  171.     TRACE(("Unimplemented error %s\n", strerror(e)));
  172.     return ERROR_NOT_IMPLEMENTED;
  173.     }
  174. }
  175.  
  176. /* handler state info */
  177.  
  178. typedef struct _unit {
  179.     struct _unit *next;
  180.  
  181.     /* Amiga stuff */
  182.     CPTR    dosbase;
  183.     CPTR    volume;
  184.     CPTR    port;    /* Our port */
  185.  
  186.     /* Native stuff */
  187.     long    unit;    /* unit number */
  188.     UnitInfo    ui;    /* unit startup info */
  189. } Unit;
  190.  
  191. typedef struct {
  192.     CPTR addr; /* addr of real packet */
  193.     long type;
  194.     long res1;
  195.     long res2;
  196.     long arg1;
  197.     long arg2;
  198.     long arg3;
  199.     long arg4;
  200. } DosPacket;
  201.  
  202. static char *
  203. bstr(CPTR addr)
  204. {
  205.     static char buf[256];
  206.     int n = get_byte(addr++);
  207.     int i;
  208.     for(i = 0; i < n; i++)
  209.     buf[i] = get_byte(addr++);
  210.     buf[i] = 0;
  211.     return buf;
  212. }
  213.  
  214. static Unit *units = NULL;
  215. static int unit_num = 0;
  216.  
  217. static Unit*
  218. find_unit(CPTR port)
  219. {
  220.     Unit* u;
  221.     for(u = units; u; u = u->next)
  222.     if(u->port == port)
  223.         break;
  224.  
  225.     return u;
  226. }
  227.  
  228. static CPTR DosAllocMem(ULONG len)
  229. {
  230.     ULONG i;
  231.     CPTR addr;
  232.  
  233.     regs.d[0] = len + 4;
  234.     regs.d[1] = 1; /* MEMF_PUBLIC */
  235.     addr = CallLib(regs.a[6], -198); /* AllocMem */
  236.  
  237.     if(addr) {
  238.     put_long(addr, len);
  239.     addr += 4;
  240.  
  241.     /* faster to clear memory here rather than use MEMF_CLEAR */
  242.     for(i = 0; i < len; i += 4)
  243.         put_long(addr + i, 0);
  244.     }
  245.  
  246.     return addr;
  247. }
  248.  
  249. static void DosFreeMem(CPTR addr)
  250. {
  251.     addr -= 4;
  252.     regs.d[0] = get_long(addr) + 4;
  253.     regs.a[1] = addr;
  254.     CallLib(regs.a[6], -210); /* FreeMem */
  255. }
  256.  
  257. static void
  258. startup(DosPacket* packet)
  259. {
  260.     int i, namelen;
  261.     char* devname = bstr(packet->arg1 << 2);
  262.     char* s;
  263.     Unit* unit;
  264.  
  265.     /* find UnitInfo with correct device name */
  266.     s = strchr(devname, ':');
  267.     if(s) *s = '\0';
  268.  
  269.     if (num_units > 1)
  270.     for(i = 0; i < num_units; i++) {
  271.         if(0 == strcmp(ui[i].devname, devname))
  272.         break;
  273.     }
  274.     else
  275.     i = 0;
  276.  
  277.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  278.     fprintf(stderr, "Failed attempt to mount device %s\n", devname);
  279.     packet->res1 = DOS_FALSE;
  280.     packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
  281.     return;
  282.     }
  283.  
  284.     unit = (Unit *) malloc(sizeof(Unit));
  285.     unit->next = units;
  286.     units = unit;
  287.  
  288.     unit->volume = 0;
  289.     unit->port = regs.a[5];
  290.     unit->unit = unit_num++;
  291.  
  292.     unit->ui.devname = ui[i].devname;
  293.     unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
  294.     unit->ui.rootdir = ui[i].rootdir;
  295.     unit->ui.readonly = ui[i].readonly;
  296.  
  297.     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
  298.  
  299.     /* fill in our process in the device node */
  300.     put_long((packet->arg3 << 2) + 8, unit->port);
  301.  
  302.     /* open dos.library */
  303.     regs.d[0] = 0;
  304.     regs.a[1] = doslibname;
  305.     unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
  306.  
  307.     {
  308.     CPTR rootnode = get_long(unit->dosbase + 34);
  309.     CPTR dos_info = get_long(rootnode + 24) << 2;
  310.     /* make new volume */
  311.     unit->volume = DosAllocMem(80 + 1 + 44);
  312.     put_long(unit->volume + 4, 2); /* Type = dt_volume */
  313.     put_long(unit->volume + 12, 0); /* Lock */
  314.     put_long(unit->volume + 16, 3800); /* Creation Date */
  315.     put_long(unit->volume + 20, 0);
  316.     put_long(unit->volume + 24, 0);
  317.     put_long(unit->volume + 28, 0); /* lock list */
  318.     put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  319.     namelen = strlen(unit->ui.volname);
  320.     put_byte(unit->volume + 44, namelen);
  321.     for(i = 0; i < namelen; i++)
  322.         put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  323.     
  324.     /* link into DOS list */
  325.     put_long(unit->volume, get_long(dos_info + 4));
  326.     put_long(dos_info + 4, unit->volume >> 2);
  327.     }
  328.     
  329.     put_long(unit->volume + 8, unit->port);
  330.     put_long(unit->volume + 32, DISK_TYPE);
  331.  
  332.     packet->res1 = DOS_TRUE;
  333. }
  334.  
  335. #ifdef HAVE_STATFS
  336. static void
  337. do_info(Unit* unit, DosPacket* packet, CPTR info)
  338. {
  339.     struct statfs statbuf;
  340. #if STATFS_NO_ARGS == 2
  341.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  342. #else
  343.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  344. #endif
  345.     {
  346.     packet->res1 = DOS_FALSE;
  347.     packet->res2 = dos_errno();
  348.     }
  349.  
  350.     put_long(info, 0); /* errors */
  351.     put_long(info + 4, unit->unit); /* unit number */
  352.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  353.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  354.     put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
  355.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  356.     put_long(info + 24, DISK_TYPE); /* disk type */
  357.     put_long(info + 28, unit->volume >> 2); /* volume node */
  358.     put_long(info + 32, 0); /* inuse */
  359.     packet->res1 = DOS_TRUE;
  360. }
  361. #else
  362. static void
  363. do_info(Unit* unit, DosPacket* packet, CPTR info)
  364. {
  365.     put_long(info, 0); /* errors */
  366.     put_long(info + 4, unit->unit); /* unit number */
  367.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  368.     put_long(info + 12, 256); /* numblocks */
  369.     put_long(info + 16, 128); /* inuse */
  370.     put_long(info + 20, 512); /* bytesperblock */
  371.     put_long(info + 24, DISK_TYPE); /* disk type */
  372.     put_long(info + 28, unit->volume >> 2); /* volume node */
  373.     put_long(info + 32, 0); /* inuse */
  374.     packet->res1 = DOS_TRUE;
  375. }
  376. #endif
  377.  
  378. static void
  379. action_disk_info(Unit* unit, DosPacket* packet)
  380. {
  381.     TRACE(("ACTION_DISK_INFO\n"));
  382.     do_info(unit, packet, packet->arg1 << 2);
  383. }
  384.  
  385. static void
  386. action_info(Unit* unit, DosPacket* packet)
  387. {
  388.     TRACE(("ACTION_INFO\n"));
  389.     do_info(unit, packet, packet->arg2 << 2);
  390. }
  391.  
  392. typedef struct key {
  393.     struct key *next;
  394.     ULONG uniq;
  395.     char *path;
  396.     int fd;
  397. } Key;
  398.  
  399. static struct key* keys = NULL;
  400.  
  401. static void
  402. free_key(Key*k)
  403. {
  404.     Key *k1;
  405.     Key *prev = NULL;
  406.     for(k1 = keys; k1; k1 = k1->next) {
  407.         if(k == k1) {
  408.             if(prev)
  409.                 prev->next = k->next;
  410.             else
  411.                 keys = k->next;
  412.             break;
  413.         }
  414.         prev = k1;
  415.     }
  416.  
  417.     if (k->fd >= 0)
  418.     close(k->fd);
  419.     free(k->path);
  420.     free(k);
  421. }
  422.  
  423. static Key*
  424. lookup_key(ULONG uniq)
  425. {
  426.     Key *k;
  427.     for(k = keys; k; k = k->next) {
  428.         if(uniq == k->uniq)
  429.             return k;
  430.     }
  431.     fprintf(stderr, "Error: couldn't find key %ld\n", uniq);
  432.     exit(1);
  433.     /* NOTREACHED */
  434.     return NULL;
  435. }
  436.  
  437. static Key*
  438. new_key(void)
  439. {
  440.     static ULONG uniq = 0;
  441.     Key *k = (Key*) malloc(sizeof(Key));
  442.     k->uniq = ++uniq;
  443.     k->fd = -1;
  444.  
  445.     k->next = keys;
  446.     keys = k;
  447.  
  448.     return k;
  449. }
  450.  
  451. static void
  452. dumplock(CPTR lock)
  453. {
  454.     if(!lock) {
  455.     fprintf(stderr, "LOCK: 0x0\n");
  456.     return;
  457.     }
  458.     fprintf(stderr,
  459.         "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
  460.         lock,
  461.         get_long(lock)<<2, lookup_key(get_long(lock+4))->path, get_long(lock+8),
  462.         get_long(lock+12), get_long(lock+16));
  463. }
  464.  
  465. static char*
  466. get_path(Unit* unit, const char *base, const char *rel)
  467. {
  468.     static char buf[1024];
  469.     char *s = buf;
  470.     char *p;
  471.     char *r;
  472.  
  473.     int i;
  474.  
  475.     TRACE(("get_path(%s,%s)\n", base, rel));
  476.  
  477.     /* root-relative path? */
  478.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
  479.     if(':' == rel[i]) {
  480.     /*base = unit->ui.rootdir;*/ rel += i+1;
  481.     }
  482.  
  483.     while(*base) {
  484.     *s++ = *base++;
  485.     }
  486.     *s = 0;
  487.     p = s; /* start of relative path */
  488.     r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
  489.  
  490.     while(*rel) {
  491.     /* start with a slash? go up a level. */
  492.     if('/' == *rel) {
  493.         while(s > r && '/' != *s)
  494.         s--;
  495.         *s = 0;
  496.         rel++;
  497.     } else {
  498.         *s++ = '/';
  499.         while(*rel && '/' != *rel) {
  500.         *s++ = *rel++;
  501.         }
  502.         *s = 0;
  503.         if('/' == *rel)
  504.         rel++;
  505.     }
  506.     }
  507.     *s = 0;
  508.  
  509. #ifdef MAKE_CASE_INSENSITIVE
  510.     TRACE(("path=\"%s\"\n", buf));
  511.     /* go through each section of the path and if it does not exist,
  512.      * scan its directory for any case insensitive matches
  513.      */
  514.     while(*p) {
  515.     char *p2 = strchr(p+1, '/');
  516.     char oldp2;
  517.     if(!p2) {
  518.         p2 = p+1;
  519.         while(*p2) p2++;
  520.     }
  521.     oldp2 = *p2;
  522.     *p2 = '\0';
  523.     if(0 != access(buf, F_OK|R_OK)) {
  524.         DIR* dir;
  525.         struct dirent* de;
  526.         /* does not exist -- check dir for case insensitive match */
  527.         *p++ = '\0'; /* was '/' */
  528.         dir = opendir(buf);
  529.         if (dir) {
  530.         while((de = readdir(dir))) {
  531. #if 0
  532.             if(0 == stricmp(de->d_name, p))    /* OLSEN */
  533. #endif
  534.             if(0 == strcasecmp(de->d_name, p))
  535.             break;
  536.         }
  537.         if(de) {
  538.             strcpy(p, de->d_name);
  539.         }
  540.         closedir(dir);
  541.         }
  542.         *--p = '/';
  543.     }
  544.     *p2 = oldp2;
  545.     p = p2;
  546.     }
  547. #endif
  548.     TRACE(("path=\"%s\"\n", buf));
  549.  
  550.     return my_strdup(buf);
  551. }
  552.  
  553. static Key*
  554. make_key(Unit* unit, CPTR lock, const char *name)
  555. {
  556.     Key *k = new_key();
  557.  
  558.     if(!lock) {
  559.     k->path = get_path(unit, unit->ui.rootdir, name);
  560.     } else {
  561.     Key*oldk = lookup_key(get_long(lock + 4));
  562. #if 0
  563.     const char *nm = strchr (name, ':');
  564.     if (nm == NULL) {
  565.         nm = name;
  566.     } else
  567.         nm++;
  568. #else
  569.     const char *nm = name;
  570. #endif
  571.     TRACE(("key: 0x%08lx", oldk->uniq));
  572.     TRACE((" \"%s\"\n", oldk->path));
  573.     k->path = get_path(unit, oldk->path, nm);
  574.     }
  575.  
  576.     TRACE(("key=\"%s\"\n", k->path));
  577.     return k;
  578. }
  579.  
  580. static Key*
  581. dup_key(Key*k)
  582. {
  583.     Key *newk = new_key();
  584.     newk->path = my_strdup(k->path);
  585.     return newk;
  586. }
  587.  
  588. static CPTR
  589. make_lock(Unit* unit, Key *key, long mode)
  590. {
  591.     /* allocate lock */
  592.     CPTR lock = DosAllocMem(20);
  593.  
  594.     put_long(lock + 4, key->uniq);
  595.     put_long(lock + 8, mode);
  596.     put_long(lock + 12, unit->port);
  597.     put_long(lock + 16, unit->volume >> 2);
  598.  
  599.     /* prepend to lock chain */
  600.     put_long(lock, get_long(unit->volume + 28));
  601.     put_long(unit->volume + 28, lock >> 2);
  602.  
  603.     DUMPLOCK(lock);
  604.     return lock;
  605. }
  606.  
  607. static void
  608. free_lock(Unit* unit, CPTR lock)
  609. {
  610.     if(!lock)
  611.     return;
  612.  
  613.     if(lock == get_long(unit->volume + 28) << 2) {
  614.     put_long(unit->volume + 28, get_long(lock));
  615.     } else {
  616.     CPTR current = get_long(unit->volume + 28);
  617.     CPTR next = 0;
  618.     while(current) {
  619.         next = get_long(current << 2);
  620.         if(lock == next << 2)
  621.         break;
  622.         current = next;
  623.     }
  624.     put_long(current << 2, get_long(lock));
  625.     }
  626.     free_key(lookup_key(get_long(lock + 4)));
  627.     DosFreeMem(lock);
  628. }
  629.  
  630. static void
  631. action_lock(Unit* unit, DosPacket* packet)
  632. {
  633.     CPTR lock = packet->arg1 << 2;
  634.     CPTR name = packet->arg2 << 2;
  635.     long mode = packet->arg3;
  636.     int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
  637.     Key *k;
  638.  
  639.     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
  640.     DUMPLOCK(lock);
  641.  
  642.     k = make_key(unit, lock, bstr(name));
  643.  
  644.     if(k && 0 == access(k->path, access_mode)) {
  645.     packet->res1 = make_lock(unit, k, mode) >> 2;
  646.     } else {
  647.     if(k)
  648.         free_key(k);
  649.     packet->res1 = 0;
  650.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  651.     }
  652. }
  653.  
  654. static void
  655. action_free_lock(Unit* unit, DosPacket* packet)
  656. {
  657.     CPTR lock = packet->arg1 << 2;
  658.     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
  659.     DUMPLOCK(lock);
  660.  
  661.     free_lock(unit, lock);
  662.  
  663.     packet->res1 = DOS_TRUE;
  664. }
  665.  
  666. static void
  667. action_dup_lock(Unit* unit, DosPacket* packet)
  668. {
  669.     CPTR lock = packet->arg1 << 2;
  670.  
  671.     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
  672.     DUMPLOCK(lock);
  673.  
  674.     if(!lock) {
  675.     packet->res1 = 0;
  676.     return;
  677.     }
  678.  
  679.     {
  680.     CPTR oldkey = get_long(lock + 4);
  681.     CPTR oldmode = get_long(lock + 8);
  682.     packet->res1 = make_lock(unit, dup_key(lookup_key(oldkey)), oldmode) >> 2;
  683.     }
  684. }
  685.  
  686. /* convert time_t to/from AmigaDOS time */
  687. const int secs_per_day = 24 * 60 * 60;
  688. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  689.  
  690. static void
  691. get_time(time_t t, long* days, long* mins, long* ticks)
  692. {
  693.     /* time_t is secs since 1-1-1970 */
  694.     /* days since 1-1-1978 */
  695.     /* mins since midnight */
  696.     /* ticks past minute @ 50Hz */
  697.  
  698.     t -= diff;
  699.     *days = t / secs_per_day;
  700.     t -= *days * secs_per_day;
  701.     *mins = t / 60;
  702.     t -= *mins * 60;
  703.     *ticks = t * 50;
  704. }
  705.  
  706. static time_t
  707. put_time(long days, long mins, long ticks)
  708. {
  709.     time_t t;
  710.     t = ticks / 50;
  711.     t += mins * 60;
  712.     t += days * secs_per_day;
  713.     t += diff;
  714.  
  715.     return t;
  716. }
  717.  
  718.  
  719. typedef struct {
  720.     ULONG uniq;
  721.     char *path;
  722.     DIR* dir;
  723. } ExamineKey;
  724.  
  725. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  726.  * some of these around
  727.  */
  728.  
  729. #define EXKEYS 100
  730. static ExamineKey examine_keys[EXKEYS];
  731. static int next_exkey = 0;
  732.  
  733. static void
  734. free_exkey(ExamineKey* ek)
  735. {
  736.     free(ek->path);
  737.     ek->path = 0;
  738.     if(ek->dir)
  739.     closedir(ek->dir);
  740. }
  741.  
  742. static ExamineKey*
  743. new_exkey(char *path)
  744. {
  745.     ULONG uniq = next_exkey;
  746.     ExamineKey* ek= &examine_keys[next_exkey++];
  747.     if(next_exkey==EXKEYS)
  748.     next_exkey = 0;
  749.     if(ek->path) {
  750.     free_exkey(ek);
  751.     }
  752.     ek->path = my_strdup(path);
  753.     ek->dir = 0;
  754.     ek->uniq = uniq;
  755.     return ek;
  756. }
  757.  
  758. static void
  759. get_fileinfo(DosPacket* packet, CPTR info, char *buf)
  760. {
  761.     struct stat statbuf;
  762.     long days, mins, ticks;
  763.  
  764.     if(-1 == stat(buf, &statbuf)) {
  765.     packet->res1 = DOS_FALSE;
  766.     packet->res2 = dos_errno();
  767.     } else {
  768.     put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  769.     {
  770.         /* file name */
  771.         int i = 8;
  772.         int n;
  773.         char *x = strrchr(buf,'/');
  774.         if(x)
  775.         x++;
  776.         else
  777.         x = buf;
  778.         TRACE(("name=\"%s\"\n", x));
  779.         n = strlen(x);
  780.         if(n > 106) n = 106;
  781.         put_byte(info + i++, n);
  782.         while(n--)
  783.         put_byte(info + i++, *x++);
  784.         while(i < 108)
  785.         put_byte(info + i++, 0);
  786.     }
  787. #ifndef __DOS__
  788.     put_long(info + 116,
  789.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  790.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  791.          (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
  792.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
  793. #else
  794.     put_long(info + 116,
  795.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  796.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  797.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)) |
  798.          (1<<6));
  799. #endif
  800.     put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  801.     put_long(info + 124, statbuf.st_size);
  802. #ifdef HAVE_ST_BLOCKS
  803.     put_long(info + 128, statbuf.st_blocks);
  804. #else
  805.     put_long(info + 128, statbuf.st_size / 512 + 1);
  806. #endif
  807.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  808.     put_long(info + 132, days);
  809.     put_long(info + 136, mins);
  810.     put_long(info + 140, ticks);
  811.     put_long(info + 144, 0); /* no comment */
  812.     packet->res1 = DOS_TRUE;
  813.     }
  814. }
  815.  
  816. static void
  817. do_examine(DosPacket* packet, ExamineKey* ek, CPTR info)
  818. {
  819.     static char buf[1024];
  820.     struct dirent* de;
  821.  
  822.     if(!ek->dir) {
  823.     ek->dir = opendir(ek->path);
  824.     }
  825.     if(!ek->dir) {
  826.     free_exkey(ek);
  827.     packet->res1 = DOS_FALSE;
  828.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  829.     return;
  830.     }
  831.  
  832.     de = readdir(ek->dir);
  833.  
  834.     while(de && (0 == strcmp(".", de->d_name) 
  835.          || 0 == strcmp("..", de->d_name)))
  836.     {
  837.     de = readdir(ek->dir);
  838.     }
  839.  
  840.     if(!de) {
  841.     TRACE(("no more entries\n"));
  842.     free_exkey(ek);
  843.     packet->res1 = DOS_FALSE;
  844.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  845.     return;
  846.     }
  847.  
  848.     TRACE(("entry=\"%s\"\n", de->d_name));
  849.  
  850.     sprintf(buf, "%s/%s", ek->path, de->d_name);
  851.  
  852.     get_fileinfo(packet, info, buf);
  853. }
  854.  
  855. static void
  856. action_examine_object(Unit* unit, DosPacket* packet)
  857. {
  858.     CPTR lock = packet->arg1 << 2;
  859.     CPTR info = packet->arg2 << 2;
  860.     char *path;
  861.     ExamineKey* ek;
  862.  
  863.     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  864.     DUMPLOCK(lock);
  865.  
  866.     if(!lock) {
  867.     path = unit->ui.rootdir;
  868.     } else {
  869.     Key*k = lookup_key(get_long(lock + 4));
  870.     path = k->path;
  871.     }
  872.  
  873.     get_fileinfo(packet, info, path);
  874.     ek = new_exkey(path);
  875.     put_long(info, ek->uniq);
  876. }
  877.  
  878. static void
  879. action_examine_next(Unit* unit, DosPacket* packet)
  880. {
  881.     CPTR lock = packet->arg1 << 2;
  882.     CPTR info = packet->arg2 << 2;
  883.  
  884.     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  885.     DUMPLOCK(lock);
  886.  
  887.     do_examine(packet, &examine_keys[get_long(info)], info);
  888. }
  889.  
  890. static void
  891. do_find(Unit* unit, DosPacket* packet, mode_t mode)
  892. {
  893.     CPTR fh = packet->arg1 << 2;
  894.     CPTR lock = packet->arg2 << 2;
  895.     CPTR name = packet->arg3 << 2;
  896.     Key *k;
  897.     struct stat st;
  898.  
  899.     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
  900.     DUMPLOCK(lock);
  901.  
  902.     k = make_key(unit, lock, bstr(name));
  903.     if(!k) {
  904.     packet->res1 = DOS_FALSE;
  905.     packet->res2 = ERROR_NO_FREE_STORE;
  906.     return;
  907.     }
  908.  
  909.     /* Fixme: may not quite be right */
  910.     if (0 == stat (k->path, &st)) {
  911.     if (S_ISDIR (st.st_mode)) {
  912.         packet->res1 = DOS_FALSE;
  913.         packet->res2 = ERROR_OBJECT_WRONG_TYPE;
  914.         return;
  915.     }
  916.     }
  917.  
  918.     k->fd = open(k->path, mode | O_BINARY, 0777);
  919.  
  920.     if(k->fd < 0) {
  921.     packet->res1 = DOS_FALSE;
  922.     packet->res2 = dos_errno();
  923.     free_key(k);
  924.     return;
  925.     }
  926.     success:
  927.     put_long(fh+36, k->uniq);
  928.  
  929.     packet->res1 = DOS_TRUE;
  930. }
  931.  
  932. static void
  933. action_find_input(Unit* unit, DosPacket* packet)
  934. {
  935.     do_find(unit, packet, O_RDONLY);
  936. }
  937.  
  938. static void
  939. action_find_output(Unit* unit, DosPacket* packet)
  940. {
  941.     if(unit->ui.readonly) {
  942.     packet->res1 = DOS_FALSE;
  943.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  944.     return;
  945.     }
  946.     do_find(unit, packet, O_WRONLY|O_CREAT|O_TRUNC);
  947. }
  948.  
  949. static void
  950. action_find_write(Unit* unit, DosPacket* packet)
  951. {
  952.     if(unit->ui.readonly) {
  953.     packet->res1 = DOS_FALSE;
  954.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  955.     return;
  956.     }
  957.     do_find(unit, packet, O_RDWR);
  958. }
  959.  
  960. static void
  961. action_end(Unit* unit, DosPacket* packet)
  962. {
  963.     Key*k;
  964.     TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
  965.  
  966.     k = lookup_key(packet->arg1);
  967.     free_key(k);
  968.     packet->res1 = DOS_TRUE;
  969. }
  970.  
  971. static void
  972. action_read(Unit* unit, DosPacket* packet)
  973. {
  974.     Key*k = lookup_key(packet->arg1);
  975.     CPTR addr = packet->arg2;
  976.     long size = packet->arg3;
  977.     int actual;
  978.     char *buf;
  979.  
  980.     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
  981.  
  982.     /* ugh this is inefficient but easy */
  983.     buf = (char *)malloc(size);
  984.     if(!buf) {
  985.     packet->res1 = -1;
  986.     packet->res2 = ERROR_NO_FREE_STORE;
  987.     return;
  988.     }
  989.  
  990.     actual = read(k->fd, buf, size);
  991.  
  992.     packet->res1 = actual;
  993.  
  994.     if(actual > 0) {
  995.     int i;
  996.     unsigned char *bp = (unsigned char *)buf;
  997.     UWORD *realpt;
  998.     if (addr & 1) { /* Eeek! */
  999.         actual--;
  1000.         put_byte(addr, *bp++);
  1001.         addr++;
  1002.     }
  1003.     if (valid_address (addr, actual)) {
  1004.         realpt = get_real_address (addr);
  1005.         for (i = 0; i < (actual & ~1); i+=2) {
  1006.         UWORD data = ((UWORD)(*bp++) << 8);
  1007.         data |= *bp++;
  1008.         *realpt++ = data;
  1009.         }
  1010.         if (actual & 1)
  1011.         put_byte (addr + actual - 1, *bp);
  1012.     } else {
  1013.        /* fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");*/
  1014.         for(i = 0; i < actual; i++)
  1015.         put_byte(addr + i, buf[i]);
  1016.     }
  1017.     } else {
  1018.     packet->res2 = dos_errno();
  1019.     }
  1020.     free(buf);
  1021. }
  1022.  
  1023. static void
  1024. action_write(Unit* unit, DosPacket* packet)
  1025. {
  1026.     Key*k = lookup_key(packet->arg1);
  1027.     CPTR addr = packet->arg2;
  1028.     long size = packet->arg3;
  1029.     char *buf;
  1030.     int i;
  1031.  
  1032.     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
  1033.  
  1034.     if(unit->ui.readonly) {
  1035.     packet->res1 = DOS_FALSE;
  1036.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1037.     return;
  1038.     }
  1039.  
  1040.     /* ugh this is inefficient but easy */
  1041.     buf = (char *)malloc(size);
  1042.     if(!buf) {
  1043.     packet->res1 = -1;
  1044.     packet->res2 = ERROR_NO_FREE_STORE;
  1045.     return;
  1046.     }
  1047.  
  1048.     for(i = 0; i < size; i++)
  1049.     buf[i] = get_byte(addr + i);
  1050.  
  1051.     packet->res1 = write(k->fd, buf, size);
  1052.     if(packet->res1 != size)
  1053.     packet->res2 = dos_errno();
  1054.  
  1055.     free(buf);
  1056. }
  1057.  
  1058. static void
  1059. action_seek(Unit* unit, DosPacket* packet)
  1060. {
  1061.     Key* k = lookup_key(packet->arg1);
  1062.     long pos = packet->arg2;
  1063.     long mode = packet->arg3;
  1064.     off_t res;
  1065.     long old;
  1066.     int whence = SEEK_CUR;
  1067.     if(mode > 0) whence = SEEK_END;
  1068.     if(mode < 0) whence = SEEK_SET;
  1069.  
  1070.     TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
  1071.  
  1072.     old = lseek(k->fd, 0, SEEK_CUR);
  1073.     res = lseek(k->fd, pos, whence);
  1074.  
  1075.     if(-1 == res)
  1076.     packet->res1 = res;
  1077.     else
  1078.     packet->res1 = old;
  1079. }
  1080.  
  1081. static void
  1082. action_set_protect(Unit* unit, DosPacket* packet)
  1083. {
  1084.     CPTR lock = packet->arg2 << 2;
  1085.     CPTR name = packet->arg3 << 2;
  1086.     ULONG mask = packet->arg4;
  1087.     struct stat statbuf;
  1088.     mode_t mode;
  1089.     Key *k;
  1090.  
  1091.     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
  1092.  
  1093.     if(unit->ui.readonly) {
  1094.     packet->res1 = DOS_FALSE;
  1095.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1096.     return;
  1097.     }
  1098.  
  1099.     k = make_key(unit, lock, bstr(name));
  1100.     if(!k) {
  1101.     packet->res1 = DOS_FALSE;
  1102.     packet->res2 = ERROR_NO_FREE_STORE;
  1103.     return;
  1104.     }
  1105.  
  1106.     if(-1 == stat(k->path, &statbuf)) {
  1107.     free_key(k);
  1108.     packet->res1 = DOS_FALSE;
  1109.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  1110.     return;
  1111.     }
  1112.  
  1113.     mode = statbuf.st_mode;
  1114.  
  1115.     if(mask & (1 << 3))
  1116.     mode &= ~S_IRUSR;
  1117.     else
  1118.     mode |= S_IRUSR;
  1119.  
  1120.     if(mask & (1 << 2) || mask & (1 << 0))
  1121.     mode &= ~S_IWUSR;
  1122.     else
  1123.     mode |= S_IWUSR;
  1124.  
  1125.     if(mask & (1 << 1))
  1126.     mode &= ~S_IXUSR;
  1127.     else
  1128.     mode |= S_IXUSR;
  1129.  
  1130.     if(-1 == chmod(k->path, mode)) {
  1131.     packet->res1 = DOS_FALSE;
  1132.     packet->res2 = dos_errno();
  1133.     } else {
  1134.     packet->res1 = DOS_TRUE;
  1135.     }
  1136.     free_key(k);
  1137. }
  1138.  
  1139. static void
  1140. action_same_lock(Unit* unit, DosPacket* packet)
  1141. {
  1142.     CPTR lock1 = packet->arg1 << 2;
  1143.     CPTR lock2 = packet->arg2 << 2;
  1144.  
  1145.     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1146.     DUMPLOCK(lock1); DUMPLOCK(lock2);
  1147.  
  1148.     if(!lock1 || !lock2) {
  1149.     packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
  1150.     } else {
  1151.     Key* key1 = lookup_key(get_long(lock1 + 4));
  1152.     Key* key2 = lookup_key(get_long(lock2 + 4));
  1153.     packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
  1154.     }
  1155. }
  1156.  
  1157. static void
  1158. action_parent(Unit* unit, DosPacket* packet)
  1159. {
  1160.     CPTR lock = packet->arg1 << 2;
  1161.     Key*k;
  1162.  
  1163.     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
  1164.  
  1165.     if(!lock) {
  1166.     packet->res1 = 0;
  1167.     packet->res2 = 0;
  1168.     return;
  1169.     }
  1170.  
  1171.     k = dup_key(lookup_key(get_long(lock + 4)));
  1172.     if(0 == strcmp(k->path, unit->ui.rootdir)) {
  1173.     free_key(k);
  1174.     packet->res1 = 0;
  1175.     packet->res2 = 0;
  1176.     return;
  1177.     }
  1178.     {
  1179.     char *x = strrchr(k->path,'/');
  1180.     if(!x) {
  1181.         free_key(k);
  1182.         packet->res1 = 0;
  1183.         packet->res2 = 0;
  1184.         return;
  1185.     } else {
  1186.         *x = '\0';
  1187.     }
  1188.     }
  1189.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1190. }
  1191.  
  1192. static void
  1193. action_create_dir(Unit* unit, DosPacket* packet)
  1194. {
  1195.     CPTR lock = packet->arg1 << 2;
  1196.     CPTR name = packet->arg2 << 2;
  1197.     Key* k;
  1198.  
  1199.     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
  1200.  
  1201.     if(unit->ui.readonly) {
  1202.     packet->res1 = DOS_FALSE;
  1203.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1204.     return;
  1205.     }
  1206.  
  1207.     k = make_key(unit, lock, bstr(name));
  1208.  
  1209.     if(!k) {
  1210.     packet->res1 = DOS_FALSE;
  1211.     packet->res2 = ERROR_NO_FREE_STORE;
  1212.     return;
  1213.     }
  1214. #ifndef AMIGA
  1215.     if(-1 == mkdir(k->path, 0777)) {
  1216. #else
  1217.     if(-1 == mkdir(k->path)) {
  1218. #endif
  1219.     packet->res1 = DOS_FALSE;
  1220.     packet->res2 = dos_errno();
  1221.     free_key(k);
  1222.     return;
  1223.     }
  1224.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1225. }
  1226.  
  1227. static void
  1228. action_delete_object(Unit* unit, DosPacket* packet)
  1229. {
  1230.     CPTR lock = packet->arg1 << 2;
  1231.     CPTR name = packet->arg2 << 2;
  1232.     Key* k;
  1233.     struct stat statbuf;
  1234.  
  1235.     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
  1236.  
  1237.     if(unit->ui.readonly) {
  1238.     packet->res1 = DOS_FALSE;
  1239.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1240.     return;
  1241.     }
  1242.  
  1243.     k = make_key(unit, lock, bstr(name));
  1244.  
  1245.     if(!k) {
  1246.     packet->res1 = DOS_FALSE;
  1247.     packet->res2 = ERROR_NO_FREE_STORE;
  1248.     return;
  1249.     }
  1250.     if(-1 == stat(k->path, &statbuf)) {
  1251.     packet->res1 = DOS_FALSE;
  1252.     packet->res2 = dos_errno();
  1253.     free_key(k);
  1254.     return;
  1255.     }
  1256.     if(S_ISDIR(statbuf.st_mode)) {
  1257.     if(-1 == rmdir(k->path)) {
  1258.         packet->res1 = DOS_FALSE;
  1259.         packet->res2 = dos_errno();
  1260.         free_key(k);
  1261.         return;
  1262.     }
  1263.     } else {
  1264.     if(-1 == unlink(k->path)) {
  1265.         packet->res1 = DOS_FALSE;
  1266.         packet->res2 = dos_errno();
  1267.         free_key(k);
  1268.         return;
  1269.     }
  1270.     }
  1271.     free_key(k);
  1272.     packet->res1 = DOS_TRUE;
  1273. }
  1274.  
  1275. static void
  1276. action_set_date(Unit* unit, DosPacket* packet)
  1277. {
  1278.     CPTR lock = packet->arg2 << 2;
  1279.     CPTR name = packet->arg3 << 2;
  1280.     CPTR date = packet->arg4;
  1281.     Key* k;
  1282. #if !defined(AMIGA)
  1283.     struct utimbuf ut;
  1284. #endif
  1285.  
  1286.     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
  1287.  
  1288.     if(unit->ui.readonly) {
  1289.     packet->res1 = DOS_FALSE;
  1290.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1291.     return;
  1292.     }
  1293.  
  1294. #if !defined(AMIGA)
  1295.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  1296. #endif
  1297.     k = make_key(unit, lock, bstr(name));
  1298.  
  1299.     if(!k) {
  1300.     packet->res1 = DOS_FALSE;
  1301.     packet->res2 = ERROR_NO_FREE_STORE;
  1302.     return;
  1303.     }
  1304. #if !defined(AMIGA)
  1305.     if(-1 == utime(k->path, &ut)) {
  1306.     packet->res1 = DOS_FALSE;
  1307.     packet->res2 = dos_errno();
  1308.     free_key(k);
  1309.     return;
  1310.     }
  1311. #endif
  1312.     free_key(k);
  1313.     packet->res1 = DOS_TRUE;
  1314. }
  1315.  
  1316. static void
  1317. action_rename_object(Unit* unit, DosPacket* packet)
  1318. {
  1319.     CPTR lock1 = packet->arg1 << 2;
  1320.     CPTR name1 = packet->arg2 << 2;
  1321.     Key* k1;
  1322.     CPTR lock2 = packet->arg3 << 2;
  1323.     CPTR name2 = packet->arg4 << 2;
  1324.     Key* k2;
  1325.  
  1326.     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
  1327.     TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
  1328.  
  1329.     if(unit->ui.readonly) {
  1330.     packet->res1 = DOS_FALSE;
  1331.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1332.     return;
  1333.     }
  1334.  
  1335.     k1 = make_key(unit, lock1, bstr(name1));
  1336.     if(!k1) {
  1337.     packet->res1 = DOS_FALSE;
  1338.     packet->res2 = ERROR_NO_FREE_STORE;
  1339.     return;
  1340.     }
  1341.     k2 = make_key(unit, lock2, bstr(name2));
  1342.     if(!k2) {
  1343.     free_key(k1);
  1344.     packet->res1 = DOS_FALSE;
  1345.     packet->res2 = ERROR_NO_FREE_STORE;
  1346.     return;
  1347.     }
  1348.  
  1349.     if(-1 == rename(k1->path, k2->path)) {
  1350.     packet->res1 = DOS_FALSE;
  1351.     packet->res2 = dos_errno();
  1352.     free_key(k1);
  1353.     free_key(k2);
  1354.     return;
  1355.     }
  1356.     free_key(k1);
  1357.     free_key(k2);
  1358.     packet->res1 = DOS_TRUE;
  1359. }
  1360.  
  1361. static void
  1362. action_current_volume(Unit* unit, DosPacket* packet)
  1363. {
  1364.     packet->res1 = unit->volume >> 2;
  1365. }
  1366.  
  1367. static void
  1368. action_rename_disk(Unit* unit, DosPacket* packet)
  1369. {
  1370.     CPTR name = packet->arg1 << 2;
  1371.     int i;
  1372.     int namelen;
  1373.  
  1374.     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
  1375.  
  1376.     if(unit->ui.readonly) {
  1377.     packet->res1 = DOS_FALSE;
  1378.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1379.     return;
  1380.     }
  1381.  
  1382.     /* get volume name */
  1383.     namelen = get_byte(name++);
  1384.     free(unit->ui.volname);
  1385.     unit->ui.volname = (char *) malloc(namelen + 1);
  1386.     for(i = 0; i < namelen; i++)
  1387.     unit->ui.volname[i] = get_byte(name++);
  1388.     unit->ui.volname[i] = 0;
  1389.  
  1390.     put_byte(unit->volume + 44, namelen);
  1391.     for(i = 0; i < namelen; i++)
  1392.     put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  1393.  
  1394.     packet->res1 = DOS_TRUE;
  1395. }
  1396.  
  1397. static void
  1398. action_is_filesystem(Unit* unit, DosPacket* packet)
  1399. {
  1400.     packet->res1 = DOS_TRUE;
  1401. }
  1402.  
  1403. static void
  1404. action_flush(Unit* unit, DosPacket* packet)
  1405. {
  1406.     /* sync(); */ /* pretty drastic, eh */
  1407.     packet->res1 = DOS_TRUE;
  1408. }
  1409.  
  1410. static ULONG
  1411. filesys_handler(void)
  1412. {
  1413.     DosPacket packet;
  1414.     Unit *unit = find_unit(regs.a[5]);
  1415.  
  1416.     /* got DosPacket in A4 */
  1417.     packet.addr = regs.a[4];
  1418.     packet.type = get_long(packet.addr + dp_Type);
  1419.     packet.res1 = get_long(packet.addr + dp_Res1);
  1420.     packet.res2 = get_long(packet.addr + dp_Res2);
  1421.     packet.arg1 = get_long(packet.addr + dp_Arg1);
  1422.     packet.arg2 = get_long(packet.addr + dp_Arg2);
  1423.     packet.arg3 = get_long(packet.addr + dp_Arg3);
  1424.     packet.arg4 = get_long(packet.addr + dp_Arg4);
  1425.  
  1426.     if(!unit) {
  1427.     startup(&packet);
  1428.     put_long(packet.addr + dp_Res1, packet.res1);
  1429.     put_long(packet.addr + dp_Res2, packet.res2);
  1430.     return 0;
  1431.     }
  1432.  
  1433.     if(!unit->volume) {
  1434.     printf("no volume\n");
  1435.     return 0;
  1436.     }
  1437.  
  1438.     switch(packet.type) {
  1439.      case ACTION_LOCATE_OBJECT:
  1440.     action_lock(unit, &packet);
  1441.     break;
  1442.  
  1443.      case ACTION_FREE_LOCK:
  1444.     action_free_lock(unit, &packet);
  1445.     break;
  1446.  
  1447.      case ACTION_COPY_DIR:
  1448.     action_dup_lock(unit, &packet);
  1449.     break;
  1450.  
  1451.      case ACTION_DISK_INFO:
  1452.     action_disk_info(unit, &packet);
  1453.     break;
  1454.  
  1455.      case ACTION_INFO:
  1456.     action_info(unit, &packet);
  1457.     break;
  1458.  
  1459.      case ACTION_EXAMINE_OBJECT:
  1460.     action_examine_object(unit, &packet);
  1461.     break;
  1462.  
  1463.      case ACTION_EXAMINE_NEXT:
  1464.     action_examine_next(unit, &packet);
  1465.     break;
  1466.  
  1467.      case ACTION_FIND_INPUT:
  1468.     action_find_input(unit, &packet);
  1469.     break;
  1470.  
  1471.      case ACTION_FIND_WRITE:
  1472.     action_find_write(unit, &packet);
  1473.     break;
  1474.  
  1475.      case ACTION_FIND_OUTPUT:
  1476.     action_find_output(unit, &packet);
  1477.     break;
  1478.  
  1479.      case ACTION_END:
  1480.     action_end(unit, &packet);
  1481.     break;
  1482.  
  1483.      case ACTION_READ:
  1484.     action_read(unit, &packet);
  1485.     break;
  1486.  
  1487.      case ACTION_WRITE:
  1488.     action_write(unit, &packet);
  1489.     break;
  1490.  
  1491.      case ACTION_SEEK:
  1492.     action_seek(unit, &packet);
  1493.     break;
  1494.  
  1495.      case ACTION_SET_PROTECT:
  1496.     action_set_protect(unit, &packet);
  1497.     break;
  1498.  
  1499.      case ACTION_SAME_LOCK:
  1500.     action_same_lock(unit, &packet);
  1501.     break;
  1502.  
  1503.      case ACTION_PARENT:
  1504.     action_parent(unit, &packet);
  1505.     break;
  1506.  
  1507.      case ACTION_CREATE_DIR:
  1508.     action_create_dir(unit, &packet);
  1509.     break;
  1510.  
  1511.      case ACTION_DELETE_OBJECT:
  1512.     action_delete_object(unit, &packet);
  1513.     break;
  1514.  
  1515.      case ACTION_RENAME_OBJECT:
  1516.     action_rename_object(unit, &packet);
  1517.     break;
  1518.  
  1519.      case ACTION_SET_DATE:
  1520.     action_set_date(unit, &packet);
  1521.     break;
  1522.  
  1523.      case ACTION_CURRENT_VOLUME:
  1524.     action_current_volume(unit, &packet);
  1525.     break;
  1526.  
  1527.      case ACTION_RENAME_DISK:
  1528.     action_rename_disk(unit, &packet);
  1529.     break;
  1530.  
  1531.      case ACTION_IS_FILESYSTEM:
  1532.     action_is_filesystem(unit, &packet);
  1533.     break;
  1534.  
  1535.      case ACTION_FLUSH:
  1536.     action_flush(unit, &packet);
  1537.     break;
  1538.  
  1539.      default:
  1540.     TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
  1541.     packet.res1 = DOS_FALSE;
  1542.     packet.res2 = ERROR_ACTION_NOT_KNOWN;
  1543.     break;
  1544.     }
  1545.  
  1546.     put_long(packet.addr + dp_Res1, packet.res1);
  1547.     put_long(packet.addr + dp_Res2, packet.res2);
  1548.     TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
  1549.  
  1550.     return 0;
  1551. }
  1552.  
  1553. static ULONG
  1554. filesys_init(void)
  1555. {
  1556.     ULONG tmp1, tmp2, configdev;
  1557.     int have36 = 0;
  1558.     int i;
  1559.  
  1560.     regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
  1561.     tmp1 = CallLib (regs.a[6], -198); /* AllocMem() */
  1562.     if (tmp1 == 0) {
  1563.     fprintf(stderr, "Not enough memory for filesystem!\n");
  1564.     return 0;
  1565.     }
  1566.  
  1567.     /* Open expansion.lib */
  1568.     regs.d[0] = 36; /* Let's try this... */
  1569.     regs.a[1] = explibname;
  1570.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1571.     if (regs.a[4])
  1572.     have36 = 1;
  1573.     else {
  1574.     regs.d[0] = 0;
  1575.     regs.a[1] = explibname;
  1576.     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
  1577.     }
  1578.     put_long (tmp1+4, fsdevname);
  1579.     put_long (tmp1+12, 0); /* Device flags */
  1580.     put_long (tmp1+16, 16); /* Env. size */
  1581.     put_long (tmp1+20, 128); /* 512 bytes/block */
  1582.     put_long (tmp1+24, 0); /* unused */
  1583.     put_long (tmp1+28, 1); /* heads */
  1584.     put_long (tmp1+32, 1); /* unused */
  1585.     put_long (tmp1+36, 32); /* secs per track */
  1586.     put_long (tmp1+40, 1); /* reserved blocks */
  1587.     put_long (tmp1+44, 0); /* unused */
  1588.     put_long (tmp1+48, 0); /* interleave */
  1589.     put_long (tmp1+52, 0); /* lowCyl */
  1590.     put_long (tmp1+56, 511); /* upperCyl */
  1591.     put_long (tmp1+60, 0); /* Number of buffers */
  1592.     put_long (tmp1+64, 0); /* Buffer mem type */
  1593.     put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
  1594.     put_long (tmp1+72, ~1); /* addMask (?) */
  1595.     put_long (tmp1+76, (ULONG)-1); /* bootPri */
  1596.     if (have36)
  1597.     put_long (tmp1+80, 0x444f5301); /* DOS\1 */
  1598.     else
  1599.     put_long (tmp1+80, 0x444f5300); /* DOS\0 */
  1600.  
  1601.     put_long (tmp1+84, 0); /* pad */
  1602.  
  1603.     /* re-use the same parameter packet to make each
  1604.      * dos node, which will then get tweaked
  1605.      */
  1606.     for(i = 0; i < num_units; i++) {
  1607.     put_long (tmp1, devnameaddr[i]);
  1608.     put_long (tmp1+8, i); /* Unit no. (not really necessary) */
  1609.     regs.a[0] = tmp1;
  1610.     tmp2 = CallLib (regs.a[4], -144); /* MakeDosNode() */
  1611.     put_long(tmp2+8, 0x0); /* dn_Task */
  1612.     put_long(tmp2+16, 0x0); /* dn_Handler */
  1613.     put_long(tmp2+20, 4000); /* dn_StackSize */
  1614.     put_long(tmp2+32, filesysseglist >> 2); /* dn_SegList */
  1615.     put_long(tmp2+36, (ULONG)-1); /* dn_GlobalVec */
  1616. #if 0 /* Not 1.3 compatible */
  1617.         configdev = CallLib(regs.a[4], -48); /* AllocConfigDev() */
  1618.  
  1619.         /* hier init der Configdev */
  1620.  
  1621.  
  1622.     regs.a[0] = tmp2;
  1623.     regs.d[0] = (ULONG)-1;
  1624.     regs.a[1] = configdev;
  1625.     regs.d[1] = 0;        /* Flags */
  1626.     CallLib (regs.a[4], -36); /* AddBootNode() */
  1627. #else
  1628.     regs.a[0] = tmp2;
  1629.     regs.d[0] = (ULONG)-1;
  1630.     regs.a[1] = 0;
  1631.     regs.d[1] = 0;        /* Flags */
  1632.     CallLib (regs.a[4], -150); /* AddDosNode() */
  1633. #endif
  1634.     }
  1635.  
  1636.     regs.a[1] = tmp1;
  1637.     regs.d[0] = 88;
  1638.     CallLib (regs.a[6], -210); /* FreeMem() */
  1639.  
  1640.     regs.a[1] = regs.a[4];
  1641.     CallLib (regs.a[6], -414); /* CloseLibrary() */
  1642.  
  1643.     return 0;
  1644. }
  1645.  
  1646. void
  1647. filesys_install(void)
  1648. {
  1649.     ULONG begin, end, resname, resid;
  1650.     int i;
  1651.  
  1652.     if(0 == num_units)
  1653.     return;
  1654.  
  1655.     resname = ds("UAEunixfs.resource");
  1656.     resid = ds("UAE unixfs 0.1");
  1657.  
  1658.     doslibname = ds("dos.library");
  1659.     fsdevname = ds("unixfs.device"); /* does not really exist */
  1660.  
  1661.     for(i = 0; i < num_units; i++) {
  1662.     devnameaddr[i] = ds(ui[i].devname);
  1663.     }
  1664.  
  1665.     begin = here();
  1666.     dw(0x4AFC); /* RTC_MATCHWORD */
  1667.     dl(begin); /* our start address */
  1668.     dl(0); /* Continue scan here */
  1669.     dw(0x0101); /* RTF_COLDSTART; Version 1 */
  1670.     dw(0x0805); /* NT_RESOURCE; pri 5 */
  1671.     dl(resname); /* name */
  1672.     dl(resid); /* ID */
  1673.     dl(here() + 4); /* Init area: directly after this */
  1674.  
  1675.     calltrap(deftrap(filesys_init)); dw(RTS);
  1676.  
  1677.     /* align */
  1678.     align(4);
  1679.     /* Fake seglist */
  1680.     dl(16);
  1681.     filesysseglist = here();
  1682.     dl(0); /* NextSeg */
  1683.  
  1684.     /* start of code */
  1685.  
  1686.     /* I don't trust calling functions that Wait() directly,
  1687.      * so here's a little bit of 68000 code to receive and send our
  1688.      * DosPackets
  1689.      */
  1690.     dw(0x2c79); dl(4);        /* move.l    $4,a6 */
  1691.     dw(0x2279); dl(0);        /* move.l    0,a1 */
  1692.     dw(0x4eae); dw(0xfeda);    /* jsr        FindTask(a6) */
  1693.     dw(0x2040);            /* move.l    d0,a0 */
  1694.     dw(0x4be8); dw(0x005c);    /* lea.l    pr_MsgPort(a0),a5 */
  1695.                 /* loop: */
  1696.     dw(0x204d);            /* move.l    a5,a0 */
  1697.     dw(0x4eae); dw(0xfe80);    /* jsr        WaitPort(a6) */
  1698.     dw(0x204d);            /* move.l    a5,a0 */
  1699.     dw(0x4eae); dw(0xfe8c);    /* jsr        GetMsg(a6) */
  1700.     dw(0x2840);            /* move.l    d0,a4 */
  1701.     dw(0x286c); dw(10);        /* move.l    LN_NAME(a4),a4 */
  1702.     calltrap(deftrap(filesys_handler));
  1703.     dw(0x226c);    dw(0);        /* move.l    dp_Link(a4),a1 */
  1704.     dw(0x206c); dw(4);        /* move.l    dp_Port(a4),a0 */
  1705.     dw(0x294d); dw(4);        /* move.l    a5,dp_Port(a4) */
  1706.     dw(0x4eae); dw(0xfe92);    /* jsr        PutMsg(a6) */
  1707.     dw(0x60d6);         /* bra.s    loop */
  1708.  
  1709.     end = here();
  1710.     org(begin + 6);
  1711.     dl(end);
  1712.  
  1713.     org(end);
  1714. }
  1715.  
  1716.